/*
* Copyright 2008 Whohoo Licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable
* law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*/
package com.googlecode.mycontainer.web.jetty;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumSet;
import java.util.EventListener;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.http.HttpServlet;
import org.eclipse.jetty.security.HashLoginService;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.server.handler.RequestLogHandler;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletContextHandler.Decorator;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.security.Password;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.WebInfConfiguration;
import com.googlecode.mycontainer.kernel.KernelRuntimeException;
import com.googlecode.mycontainer.kernel.deploy.SimpleDeployer;
import com.googlecode.mycontainer.kernel.reflect.ReflectUtil;
import com.googlecode.mycontainer.web.ContextWebServer;
import com.googlecode.mycontainer.web.FilterDesc;
import com.googlecode.mycontainer.web.Realm;
import com.googlecode.mycontainer.web.Realm.UserRole;
import com.googlecode.mycontainer.web.ServletDesc;
import com.googlecode.mycontainer.web.WebServerDeployer;
public class JettyServerDeployer extends WebServerDeployer implements SimpleDeployer {
private static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(JettyServerDeployer.class);
private static final long serialVersionUID = 3380253274628567229L;
public static final String JETTY_USE_FILE_MAPPTED_BUFFER = "org.eclipse.jetty.servlet.Default.useFileMappedBuffer";
private Server server;
private List<Decorator> decorators = new ArrayList<ServletContextHandler.Decorator>();
public JettyServerDeployer() {
server = new Server();
System.setProperty("com.sun.faces.InjectionProvider",
"com.googlecode.mycontainer.jsfprovider.MyContainerInjectionProvider");
RequestLogHandler requestLogHandler = new RequestLogHandler();
requestLogHandler.setRequestLog(new JettyRequestLogImpl());
requestLogHandler.setServer(server);
// server.addBean(requestLogHandler);
}
public Server getServer() {
return server;
}
@Override
protected Object getResource() {
return server;
}
@Override
public void shutdown() {
LOG.info("Shutting down Jetty web server...");
try {
server.stop();
server.join();
} catch (Exception e) {
throw new KernelRuntimeException(e);
}
super.shutdown();
}
@Override
public int bindPort(int port) {
try {
ServerConnector http = new ServerConnector(server);
http.setHost("0.0.0.0");
http.setPort(port);
http.setIdleTimeout(30000);
server.addConnector(http);
if (server.isStarted()) {
http.start();
}
return http.getLocalPort();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public void bindSSLPort(SslConnectorInfo info) {
try {
Connector connector = info.createConnector(server);
server.addConnector(connector);
if (server.isStarted()) {
connector.start();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public void deploy() {
try {
deployWebContexts();
server.start();
} catch (Exception e) {
throw new KernelRuntimeException(e);
}
super.deploy();
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private void deployWebContexts() {
List<ContextWebServer> webContexts = getWebContexts();
Handler[] handlers = new Handler[webContexts.size()];
int i = 0;
for (ContextWebServer contextWebServer : webContexts) {
ServletContextHandler handler;
if (contextWebServer.getResources() != null) {
handler = new WebAppContext(contextWebServer.getResources(), contextWebServer.getContext());
} else {
handler = new ServletContextHandler(null, contextWebServer.getContext(),
ServletContextHandler.SESSIONS | ServletContextHandler.SECURITY);
handler.addServlet(DefaultServlet.class, "/*");
}
handler.setAttribute(WebInfConfiguration.CONTAINER_JAR_PATTERN,
".*/.*jsp-api-[^/]*\\.jar$|.*/.*jsp-[^/]*\\.jar$|.*/.*taglibs[^/]*\\.jar$|.*/.*jstl[^/]*\\.jar$|.*/.*jsf-impl-[^/]*\\.jar$|.*/.*javax.faces-[^/]*\\.jar$|.*/.*myfaces-impl-[^/]*\\.jar$");
// performRemoveTagLibConfiguration((WebAppContext) handler);
Set<Entry<String, Object>> attrs = contextWebServer.getAttributes().entrySet();
for (Entry<String, Object> entry : attrs) {
handler.setAttribute(entry.getKey(), entry.getValue());
}
Set<Entry<String, String>> params = contextWebServer.getInitParameters().entrySet();
for (Entry<String, String> entry : params) {
handler.setInitParameter(entry.getKey(), entry.getValue());
}
configWindows(handler);
List<Object> listeners = contextWebServer.getListeners();
for (Object listener : listeners) {
if (listener instanceof String) {
listener = ReflectUtil.classForName((String) listener);
}
if (listener instanceof Class) {
listener = ReflectUtil.newInstance((Class) listener);
}
handler.addEventListener((EventListener) listener);
}
List<FilterDesc> filters = contextWebServer.getFilters();
for (FilterDesc desc : filters) {
Object filter = desc.getFilter();
if (filter instanceof Filter) {
FilterHolder holder = new FilterHolder((Filter) filter);
handler.addFilter(holder, desc.getPath(), EnumSet.of(DispatcherType.REQUEST));
} else if (filter instanceof FilterHolder) {
handler.addFilter((FilterHolder) filter, desc.getPath(), EnumSet.of(DispatcherType.REQUEST));
} else if (filter instanceof Class) {
handler.addFilter((Class) filter, desc.getPath(), EnumSet.of(DispatcherType.REQUEST));
} else {
handler.addFilter((String) filter, desc.getPath(), EnumSet.of(DispatcherType.REQUEST));
}
}
List<ServletDesc> servlets = contextWebServer.getServlets();
for (ServletDesc desc : servlets) {
Object servlet = desc.getServlet();
if (servlet instanceof HttpServlet) {
ServletHolder holder = new ServletHolder((HttpServlet) servlet);
handler.addServlet(holder, desc.getPath());
} else if (servlet instanceof ServletHolder) {
handler.addServlet((ServletHolder) servlet, desc.getPath());
} else if (servlet instanceof Class) {
handler.addServlet((Class) servlet, desc.getPath());
} else {
handler.addServlet((String) servlet, desc.getPath());
}
}
for (Decorator decorator : decorators) {
handler.addDecorator(decorator);
}
handlers[i++] = handler;
}
ContextHandlerCollection contexts = new ContextHandlerCollection();
contexts.setHandlers(handlers);
server.setHandler(contexts);
}
private void configWindows(ServletContextHandler handler) {
String os = System.getProperty("os.name").toLowerCase();
if (os.indexOf("win") >= 0 && handler.getInitParameter(JETTY_USE_FILE_MAPPTED_BUFFER) == null) {
if (LOG.isDebugEnabled()) {
LOG.debug("Windows detected (" + os + "). Turning " + JETTY_USE_FILE_MAPPTED_BUFFER + " off to "
+ handler);
}
handler.setInitParameter(JETTY_USE_FILE_MAPPTED_BUFFER, "false");
}
}
// private void performRemoveTagLibConfiguration(WebAppContext
// contextHandler) {
// ArrayList<String> configs = new ArrayList<String>(
// Arrays.asList(contextHandler.getConfigurationClasses()));
// boolean remove = configs
// .remove("org.mortbay.jetty.webapp.TagLibConfiguration");
// if (remove) {
// contextHandler.setConfigurationClasses(configs
// .toArray(new String[configs.size()]));
// }
// LOG.info("org.mortbay.jetty.webapp.TagLibConfiguration removed: "
// + remove);
// }
public JettyServerDeployer addDecorator(Decorator decorator) {
this.decorators.add(decorator);
return this;
}
@Override
public void addRealm(Realm realm) {
HashLoginService loginService = new HashLoginService();
loginService.setName(realm.getName());
Collection<UserRole> users = realm.getUsers().values();
for (UserRole user : users) {
String[] roles = user.getRoles().toArray(new String[0]);
Password password = new Password(user.getPassword());
loginService.putUser(user.getUser(), password, roles);
}
server.addBean(loginService);
}
public static void main(String[] args) throws Exception {
Server server = new Server(8080);
WebAppContext webapp1 = new WebAppContext();
webapp1.setContextPath("/ctx1");
webapp1.setResourceBase("target");
WebAppContext webapp2 = new WebAppContext();
webapp2.setContextPath("/ctx2");
webapp2.setResourceBase("src");
ContextHandlerCollection contexts = new ContextHandlerCollection();
contexts.setHandlers(new Handler[] { webapp1, webapp2 });
server.setHandler(contexts);
server.start();
server.join();
}
}